/*
 * File.java
 * 
 * This file is part of Netuno Psamata.
 * 
 * CajuScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3, or (at your option) 
 * any later version.
 * 
 * CajuScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with CajuScript.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.netuno.psamata.io;

import java.io.InputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

/**
 * File.
 * @author eduveks
 */
public class File {
    /**
     * Path.
     */
    private String path = "";
    /**
     * Real Path.
     */
    private String physicPath = "";
    /**
     * Content Type.
     */
    private String contentType = "";
    /**
     * Bytes.
     */
    private ByteArrayInputStream bytes;
    /**
     * File.
     * @param filePath Path
     * @param fileContentType Content Type
     * @param fileBytes Bytes
     */
    public File(final String filePath, final String fileContentType, final ByteArrayInputStream fileBytes) {
        path = filePath;
        physicPath = "";
        contentType = fileContentType;
        bytes = fileBytes;
    }
    /**
     * File.
     * @param filePath Path
     * @param filePhysicPath Physic Path
     * @param fileContentType Content Type
     */
    public File(final String filePath, final String filePhysicPath, final String fileContentType) {
        path = filePath;
        physicPath = filePhysicPath;
        contentType = fileContentType;
    }
    /**
     * Get Path.
     * @return Path
     */
    public final String getPath() {
        return path;
    }
    /**
     * Get Name.
     * @return Name
     */
    public static String getName(String path) {
        String name = path;
        if (name.indexOf(java.io.File.separator) > -1) {
            name = name.substring(name.lastIndexOf(java.io.File.separator) + 1);
        }
        if (name.indexOf("\\") > -1) {
            name = name.substring(name.lastIndexOf("\\") + 1);
        }
        if (name.indexOf("/") > -1) {
            name = name.substring(name.lastIndexOf("/") + 1);
        }
        return name;
    }
    /**
     * Physic Path.
     * @return Path
     */
    public final String getPhysicPath() {
        return physicPath;
    }
    /**
     * Get Content Type.
     * @return Content Type
     */
    public final String getContentType() {
        return contentType;
    }
    /**
     * Get Input Stream.
     * @return Input Stream
     */
    public final InputStream getInputStream() {
        if (physicPath.length() == 0) {
            return bytes;
        } else {
            try {
                return (InputStream)new FileInputStream(physicPath);
            } catch (Exception e) {
                return null;
            }
        }
    }
    /**
     * Get Bytes.
     * @return Bytes
     */
    public final byte[] getBytes() {
        if (physicPath.length() == 0) {
        	try {
	        	byte[] fullBytes = new byte[bytes.available()];
	        	bytes.read(fullBytes);
	        	return fullBytes;
        	} catch (Exception e) {
                return null;
            } finally {
                try {
                	bytes.close();
                } catch(Exception e) { }
            }
        } else {
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(physicPath);
                byte[] b = new byte[fis.available()];
                fis.read(b);
                return b;
            } catch (Exception e) {
                return null;
            } finally {
                try {
                    fis.close();
                } catch(Exception e) { }
            }
        }
    }
    /**
     * Save file.
     * @param pathToWriteFile Path to save file.
     * @throws IOException Exception
     */
    public final void save(final String pathToWriteFile) throws IOException {
        delete(pathToWriteFile);
        if (physicPath.equals("")) {
            FileOutputStream out = new FileOutputStream(pathToWriteFile);
            byte[] bytesBuffer = new byte[1024];
            while (true) {
            	int bytesReaded = bytes.read(bytesBuffer);
            	out.write(bytesBuffer);
            	if (bytesReaded != bytesBuffer.length) {
                    break;
            	}
            }
            bytes.close();
            out.close();
        } else {
            (new java.io.File(physicPath)).renameTo(new java.io.File(pathToWriteFile));
            physicPath = pathToWriteFile;
        }
    }
    /**
     * Delete.
     */
    public static void delete(String path) {
        java.io.File f = new java.io.File(path);
        if (f.exists() && f.isFile()) {
            f.delete();
        }
    }
    /**
     * Copy file.
     * @param sourceFile Source file path.
     * @param destFile Destination file or folder path.
     * @return Destination file.
     * @throws IOException Exception
     */
    public static java.io.File copy(String sourceFilePath, String destPath) throws IOException {
        return copy(new java.io.File(sourceFilePath), new java.io.File(destPath));
    }
    /**
     * Copy file.
     * @param sourceFile Source file.
     * @param destFile Destination file or folder.
     * @return Destination file.
     * @throws IOException Exception
     */
    public static java.io.File copy(java.io.File sourceFile, java.io.File dest) throws IOException {
        java.io.File destFile = null;
        if (dest.isDirectory()) {
            destFile = new java.io.File(dest.getAbsolutePath().concat(java.io.File.separator).concat(sourceFile.getName()));
        } else {
            destFile = dest;
        }
        if (destFile.exists()) {
            destFile.delete();
        }
        destFile.createNewFile();
        final ReadableByteChannel sourceChannel = Channels.newChannel(new FileInputStream(sourceFile));
        final WritableByteChannel destChannel = Channels.newChannel(new FileOutputStream(destFile));
        final ByteBuffer buffer = ByteBuffer.allocateDirect(1 * 1024);
        try {
            while (sourceChannel.read(buffer) != -1) {
                buffer.flip();
                destChannel.write(buffer);
                buffer.compact();
            }
            buffer.flip();
            while (buffer.hasRemaining()) {
                destChannel.write(buffer);
            }
        } finally {
            sourceChannel.close();
            destChannel.close();
        }
        return destFile;
    }

    /**
     * Available.
     * @return File size.
     */
    public final int available() {
        if (physicPath.length() == 0) {
            return bytes.available();
        } else {
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(physicPath);
                return fis.available();
            } catch (Exception e) {
                return -1;
            } finally {
                try {
                    fis.close();
                } catch(Exception e) { }
            }
        }
    }
}
